package edu.mercer.sse.tests.web;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import edu.mercer.sse.tasks.web.DownloadURLFunction;
import edu.mercer.sse.tasks.web.URLRetrieval;


/**
 * JUnit test of ThreadProxy for the StringBuilder Object type.<p>
 * 
 * Test Thread Object Proxy Implementation using single-threaded execution.<p>
 * 
 * Test thread-global storage for single-thread across multiple Callable 
 * 	class instances.<p>
 */

public class TestSingleThread
{
	private final static String KNOWN_WEBSITE = "http://gain.mercer.edu";
	
	private static Integer _knownwebsiteSize = 0;

	final private ExecutorService _threadEx = Executors
			.newSingleThreadExecutor();

	
	/**
	 * Download contents from known, existing website.<p>
	 * 
	 * Retrieve size for use in test.<p>
	 */
	
	@Before
	public void setUp()
	{
		_knownwebsiteSize = new DownloadURLFunction().apply( KNOWN_WEBSITE )
				.length();
		
		assertTrue( _knownwebsiteSize > 0 );
		
	}//method
	
	
	/**
	 * Test thread-global storage.<p>
	 * 
	 * Download contents of URL's. Ensure contents are appended to 
	 * 	thread-global StringBuilder instance(s) when desired. Append occurs 
	 * 	across class/object boundaries. <p>
	 * 
	 * @throws InterruptedException - thread interrupted
	 * 
	 * @throws ExecutionException - URLConnection, Security Manager or other 
	 * 	errors wrapped
	 */
	
	@Test
	public void test() throws InterruptedException, 
							  ExecutionException
	{
		final ArrayList<URLRetrieval> tasks = new ArrayList<>();
		
		/* 
		 * output should be appended to single thread-global StringBuilder 
		 * with key of '1' 
		 */
		
		tasks.add( new URLRetrieval(KNOWN_WEBSITE, 1) );
		tasks.add( new URLRetrieval(KNOWN_WEBSITE, 1) );
		
		/* 
		 * output should be placed in separate thread-global StringBuilder 
		 * instance with key of '2' for this same thread 
		 */
		
		tasks.add( new URLRetrieval(KNOWN_WEBSITE, 2) );

		final List<Future<String>> taskResults = _threadEx.invokeAll(tasks);		
		
		/* size should equal @Before step download */
		
		assertEquals( "website 1st download: size found unexpected", 
				_knownwebsiteSize, 
				
				new ParseSizeFunction().apply( taskResults.get(0).get() ));

		/* 
		 * size should double, as thread-global StringBuilder is appended to 
		 */
		
		assertEquals( "website 2nd download: size found unexpected", 
				new Integer( _knownwebsiteSize * 2 ), 
				
				new ParseSizeFunction().apply( taskResults.get(1).get() ));
		
		/* 
		 * size should equal @Before step download, as using new thread-global 
		 * instance of StringBuilder 
		 */
		
		assertEquals( "website 3rd download: size found unexpected", 
				_knownwebsiteSize, 
				
				new ParseSizeFunction().apply( taskResults.get(2).get() ));
				
	}//method
	

	/**
	 * Shutdown executor service.<p>
	 */
	
	@After
	public void cleanUp()
	{
		_threadEx.shutdown();
		
	}//method

	
}//class


